#include "MyEventQueue.hpp"

MyCoEvent eventqueu_add_event;

void MyEventQueue::Register(int event_id, MyEventListener& listener)
{
    if (m_table.Find(event_id) < 0)
    {
        m_table.Add(event_id, Vector<MyEventListener>());
    }
    m_table.GetAdd(event_id).Add(listener);
}

void MyEventQueue::Unregister(int event_id, MyEventListener& listener)
{
    int i = m_table.Find(event_id);
    if (i >= 0)
    {
        Vector<MyEventListener>& listeners = m_table[i];
        for (int j = 0; j < listeners.GetCount(); j++)
        {
            if (listeners[j] == listener)
            {
                listeners.Remove(j);
                break;
            }
        }
    }
}


void MyEventQueue::PostEvent(const MyEvent& e)
{
    m_queue.AddTail(e);
    eventqueu_add_event.Broadcast();
}

void MyPostEvent(int event_id, std::initializer_list<String> event_data)
{
    MyEvent e(event_id);
    for (auto& data : event_data)
    {
        e.Add(data);
    }
    MyEventQueue::GetGlobalEventQueue().PostEvent(e);
}

void MyRegisterEvent(int event_id, MyEventListener&& listener)
{
    MyEventQueue::GetGlobalEventQueue().Register(event_id, listener);
}

void MyEventQueue::ProcessEvent(void)
{
    //process all events. PopHead() will remove the event from the queue.
    while (m_queue.GetCount() > 0)
    {
        Value v = m_queue.PopHead();
        // MyEvent e = v;
        const MyEvent &e = v.To<MyEvent>();
        int i = m_table.Find(e.event_id);
        if (i >= 0)
        {
            Vector<MyEventListener>& listeners = m_table[i];
            for (int j = 0; j < listeners.GetCount(); j++)
            {
                listeners[j](v);
            }
        }
    }
}


void MyEventQueueThread(void)
{

	while(!Thread::IsShutdownThreads()) 
    {
        MyEventQueue::GetGlobalEventQueue().ProcessEvent();
        eventqueu_add_event.Wait();
    }
}

void StartEventQueueThread()
{
    Thread::AtShutdown([] {
        eventqueu_add_event.Broadcast();
        MyEventQueue::GetGlobalEventQueue().ProcessEvent();
    });
    Thread::StartNice(MyEventQueueThread);
}

#ifdef PLATFORM_WIN32
MyTime MyGetSysTime() 
{
	SYSTEMTIME st;
	GetLocalTime(&st);
	return MyTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
}

MyTime GetUtcTime() {
	SYSTEMTIME st;
	GetSystemTime(&st);
	return MyTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
}

#endif

String Format(MyTime time)
{
    return Format("[%02d:%02d:%02d.%03d]", time.hour, time.minute, time.second, time.milliseconds);
}
